/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header: https://192.168.1.224/svn/elancom/product/elancom-platform/trunk/src/main/java/com/elancom/framework/dao/CriteriaSelect.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Id: CriteriaSelect.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Author: lanzhouxue $
 * $Date: 2012-07-02 11:09:12 +0800 (周一, 02 七月 2012) $
 * $Revision: 1034 $
 */
package com.elancom.framework.dao;

import java.util.ArrayList;
import java.util.List;

import com.elancom.framework.dao.enums.FetchMode;
import com.elancom.framework.dao.enums.JoinMode;
import com.elancom.framework.dao.enums.MatchMode;
import com.elancom.framework.dao.expression.And;
import com.elancom.framework.dao.expression.Between;
import com.elancom.framework.dao.expression.Condition;
import com.elancom.framework.dao.expression.Empty;
import com.elancom.framework.dao.expression.Equal;
import com.elancom.framework.dao.expression.GreaterEqual;
import com.elancom.framework.dao.expression.GreaterThan;
import com.elancom.framework.dao.expression.In;
import com.elancom.framework.dao.expression.LessEqual;
import com.elancom.framework.dao.expression.LessThan;
import com.elancom.framework.dao.expression.Like;
import com.elancom.framework.dao.expression.Not;
import com.elancom.framework.dao.expression.NotEmpty;
import com.elancom.framework.dao.expression.NotNull;
import com.elancom.framework.dao.expression.Null;
import com.elancom.framework.dao.expression.Or;
import com.elancom.framework.dao.expression.Size;
import com.elancom.framework.entity.AbstractEntity;

/**
 * @author elancom
 * @date Apr 13, 2012
 */
public abstract class CriteriaSelect {
	private Class<? extends AbstractEntity> entityClass = null;
	private String entityAlias = null;
	private final List<Condition> conditiones = new ArrayList<Condition>();
	private final List<AssociationAlias> aliases = new ArrayList<AssociationAlias>(3);
	private final List<AssociationFetchMode> fetchModes = new ArrayList<AssociationFetchMode>(3);

	public CriteriaSelect() {
		super();
	}

	public CriteriaSelect(Class<? extends AbstractEntity> entityClass) {
		super();
		this.entityClass = entityClass;
	}

	private void add(Condition condition) {
		conditiones.add(condition);
	}

	public CriteriaSelect and(Condition... conditions) {
		add(new And(conditions));
		return this;
	}

	public CriteriaSelect between(String propertyName, Object left, Object right) {
		add(new Between(propertyName, left, right));
		return this;
	}

	public CriteriaSelect createAlias(String association, String alias) {
		aliases.add(new AssociationAlias(association, alias));
		return this;
	}

	public CriteriaSelect createAlias(String association, String alias, JoinMode mode) {
		aliases.add(new AssociationAlias(association, alias, mode));
		return this;
	}

	public CriteriaSelect eq(String propertyName, Object value) {
		add(new Equal(propertyName, value, false));
		return this;
	}

	public CriteriaSelect eq(String propertyName, Object value, boolean isTargetProperty) {
		add(new Equal(propertyName, value, isTargetProperty));
		return this;
	}

	public CriteriaSelect ge(String propertyName, Object value) {
		add(new GreaterEqual(propertyName, value, false));
		return this;
	}

	public List<AssociationAlias> getAliases() {
		return aliases;
	}

	public List<Condition> getCondtions() {
		return conditiones;
	}

	public String getEntityAlias() {
		return entityAlias;
	}

	public Class<? extends AbstractEntity> getEntityClass() {
		return entityClass;
	}

	public String getEntiyAlias() {
		return entityAlias;
	}

	public List<AssociationFetchMode> getFetchModes() {
		return fetchModes;
	}

	public CriteriaSelect gt(String propertyName, Object value) {
		add(new GreaterThan(propertyName, value, false));
		return this;
	}

	public CriteriaSelect in(String propertyName, Object values) {
		add(new In(propertyName, values));
		return this;
	}

	public CriteriaSelect isEmpty(String property) {
		add(new Empty(property));
		return this;
	}

	public CriteriaSelect isNotEmpty(String property) {
		add(new NotEmpty(property));
		return this;
	}

	public CriteriaSelect isNotNull(String property) {
		add(new NotNull(property));
		return this;
	}

	public CriteriaSelect isNull(String property) {
		add(new Null(property));
		return this;
	}

	public CriteriaSelect le(String propertyName, Object value) {
		add(new LessEqual(propertyName, value, false));
		return this;
	}

	public CriteriaSelect like(String propertyName, Object value) {
		add(new Like(propertyName, value.toString(), MatchMode.EXACT));
		return this;
	}

	public CriteriaSelect like(String propertyName, Object value, MatchMode mode) {
		add(new Like(propertyName, value.toString(), mode));
		return this;
	}

	public CriteriaSelect lt(String propertyName, Object value) {
		add(new LessThan(propertyName, value, false));
		return this;
	}

	public CriteriaSelect not(Condition condition) {
		add(new Not(condition));
		return this;
	}

	public CriteriaSelect or(Condition... confConditiones) {
		add(new Or(confConditiones));
		return this;
	}

	public Condition pop() {
		final int size = conditiones.size();
		if (size > 0) {
			return conditiones.remove(size - 1);
		}
		return null;
	}

	public void setEntityAlias(String entityAlias) {
		this.entityAlias = entityAlias;
	}

	public void setEntityClass(Class<? extends AbstractEntity> entityClass) {
		this.entityClass = entityClass;
	}

	public void setEntityClass(Class<? extends AbstractEntity> entityClass, String entityAlias) {
		this.entityClass = entityClass;
		this.entityAlias = entityAlias;
	}

	public CriteriaSelect setFetchMode(String association, FetchMode mode) {
		fetchModes.add(new AssociationFetchMode(association, mode));
		return this;
	}

	public CriteriaSelect sizeEq(String property, int size) {
		add(new Size(property, size, "="));
		return this;
	}

	public CriteriaSelect sizeGe(String property, int size) {
		add(new Size(property, size, ">="));
		return this;
	}

	public CriteriaSelect sizeGt(String property, int size) {
		add(new Size(property, size, ">"));
		return this;
	}

	public CriteriaSelect sizeLe(String property, int size) {
		add(new Size(property, size, "<="));
		return this;
	}

	public CriteriaSelect sizeLt(String property, int size) {
		add(new Size(property, size, "<"));
		return this;
	}

	public CriteriaSelect sizeNe(String property, int size) {
		add(new Size(property, size, "!="));
		return this;
	}
}
